package se.sweco.ws.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import se.sweco.ws.DataStore;

public class DataStoreImpl implements DataStore {
	
	private Semaphore lock;
	private final DocumentBuilder builder;
	private int taxScale;
	private ArrayList<TrafficData> trafficData;
	private List<Route> routes;

	public DataStoreImpl(String routesFile) throws ParserConfigurationException {
		builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		trafficData = new ArrayList<TrafficData>();
		lock = new Semaphore(1);
		System.err.println("Getting routes...");
		routes = GeoDataParser.parseRoutes(routesFile);
		if (System.getProperty("tinfo.tax.scale") != null) {
			taxScale = Integer.parseInt(System.getProperty("tinfo.tax.scale"));
		} else {
			taxScale = 1;
		}
	}

	@Override
	public Document getTaxRate(double lon, double lat) {
		Document doc = builder.newDocument();
		Element response, tax, tariff;
		response = doc.createElement("response");
		doc.appendChild(response);
		tax = doc.createElement("tax");
		response.appendChild(tax);
		tariff = doc.createElement("tariff");
		Random r = new Random();
		tariff.setTextContent(String.valueOf(taxScale * r.nextDouble()));
		tax.appendChild(tariff);
		
		return doc;
	}

	@Override
	public Document getTrafficData(double lon, double lat, double radius) {
		Document doc = builder.newDocument();
		Element response, traffic, child;
		response = doc.createElement("response");

		Coord c = new Coord(lon, lat);
		try {
			lock.acquire();
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
		}
		for (TrafficData d : trafficData) {
			if (c.getDistance(d.startCoord) < radius || c.getDistance(d.endCoord) < radius) {
				traffic = doc.createElement("traffic");
				
				child = doc.createElement("startLat");
				child.setTextContent(Double.toString(d.startCoord.lat));
				traffic.appendChild(child);
				
				child = doc.createElement("startLon");
				child.setTextContent(Double.toString(d.startCoord.lon));
				traffic.appendChild(child);
				
				child = doc.createElement("endLat");
				child.setTextContent(Double.toString(d.endCoord.lat));
				traffic.appendChild(child);
				
				child = doc.createElement("endLon");
				child.setTextContent(Double.toString(d.endCoord.lon));
				traffic.appendChild(child);
				
				child = doc.createElement("time");
				child.setTextContent(Double.toString(d.time));
				traffic.appendChild(child);
				
				child = doc.createElement("reliability");
				child.setTextContent(Integer.toString(d.reliability));
				traffic.appendChild(child);
				
				response.appendChild(traffic);
			}
		}
		lock.release();

		doc.appendChild(response);
		return doc;
	}

	@Override
	public void addTrafficData(List data) {
		if (data == null) {
			return;
		}
		final List<TrafficData> td = data;
		try {
			lock.acquire();
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
		}
		for (TrafficData d : td) {
			trafficData.add(d);
		}
		lock.release();
		/* TODO: maybe sort data? */
	}

	@Override
	public void clearTrafficData() {
		try {
			lock.acquire();
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
		}
		trafficData.clear();
		lock.release();
	}

	@Override
	public List getRoutes() {
		return routes;
	}
}
